﻿/**************************************************************
 *
 * 唯一标识：40cd6bb5-c032-4219-ae06-9f27f2fe5f9a
 * 命名空间：Sgr.UPMS.Infrastructure.Repositories
 * 创建时间：2023/8/28 9:32:32
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using Microsoft.EntityFrameworkCore;
using Sgr.Domain.Entities.Auditing;
using Sgr.Domain.Repositories;
using Sgr.EntityFrameworkCore;
using Sgr.Exceptions;
using Sgr.Generator;
using Sgr.UPMS.Domain.UserTokens;

namespace Sgr.UPMS.Infrastructure.Repositories
{
    /// <summary>
    /// 用户刷新令牌仓储实现
    /// </summary>
    /// <remarks>
    /// 实现了用户刷新令牌的数据访问操作：
    /// - 令牌的基础CRUD操作
    /// - 令牌查询和验证
    /// - 过期令牌处理
    /// </remarks>
    public class UserRefreshTokenRepository<TDbContext> : EfCoreRepositoryOfTEntityAndTPrimaryKey<TDbContext, UserRefreshToken, long>, IUserRefreshTokenRepository where TDbContext : UnitOfWorkDbContext
    {
        private readonly ISegmentNumIdGenerator _numberIdGenerator;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContextProvider"></param>
        /// <param name="auditedOperator">审计操作者</param>
        /// <param name="numberIdGenerator">数字ID生成器</param>
        /// <exception cref="BusinessException">参数为空时抛出异常</exception>
        public UserRefreshTokenRepository(
            IDbContextProvider<TDbContext> dbContextProvider,
            IAuditedOperator auditedOperator,
            ISegmentNumIdGenerator numberIdGenerator)
            : base(dbContextProvider, auditedOperator)
        {
            _numberIdGenerator = numberIdGenerator ?? throw new ArgumentNullException(nameof(numberIdGenerator));
        }

        /// <summary>
        /// 检查并设置主键Id
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns></returns>
        protected override async Task CheckAndSetIdAsync(UserRefreshToken entity, CancellationToken cancellationToken = default)
        {
            if (entity.Id == 0)
                entity.Id = await _numberIdGenerator.GetUniqueIdAsync(UpmsConstant.DEFAULT_SEGMENT_KEY, cancellationToken);
        }

        /// <summary>
        /// 根据刷新令牌获取实体
        /// </summary>
        /// <param name="refreshToken">刷新令牌</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>刷新令牌实体，不存在返回null</returns>
        /// <exception cref="ArgumentException">当refreshToken为空时抛出</exception>
        public async Task<UserRefreshToken?> GetByRefreshTokenAsync(
            string refreshToken,
            CancellationToken cancellationToken = default)
        {
            Check.StringNotNullOrEmpty(refreshToken, nameof(refreshToken));

            var query = await GetQueryableAsync(cancellationToken);
            return await query
                .AsNoTracking()
                .FirstOrDefaultAsync(f => f.Token == refreshToken, cancellationToken);
        }

        public async Task RemoveExpiredByUserIdAsync(long userId,
           CancellationToken cancellationToken = default)
        {
            if (userId <= 0)
                throw new ArgumentException("用户ID必须大于0", nameof(userId));

            var query = await GetQueryableAsync(cancellationToken);
            var expiredTokens = await query
                .Where(f => f.UserId == userId && f.Expires <= DateTime.UtcNow)
                .ToListAsync(cancellationToken); // 使用异步版本

            if (expiredTokens.Count > 0)
            {
                await BulkDeleteAsync(expiredTokens, cancellationToken); // 批量删除，性能更好
            }
        }
    }
}